// [吃面-做面模型]

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>

#define THREAD_COUNT 2

int g_bowl = 0;  //临界资源，0：空 1：有面
pthread_mutex_t g_lock;  //临界资源互斥锁
pthread_cond_t g_cond_eat;  //吃面线程条件变量
pthread_cond_t g_cond_make;  //做面线程条件变量

// 吃面线程入口函数
void* eat_thread_start(void* arg)
{
    while(1)
    {
        // 加锁
        pthread_mutex_lock(&g_lock);
        while(g_bowl == 0)
        {
            printf("吃面人：没面，等待~\n");
            // 吃面线程进入等待队列
            pthread_cond_wait(&g_cond_eat, &g_lock);
        }
        printf("EAT: 有g_bowl:%d，吃一碗\n", g_bowl--);
        // 解锁
        pthread_mutex_unlock(&g_lock);
        // 通知做面等待队列中的做面线程做面
        pthread_cond_signal(&g_cond_make);
    }
}

// 做面线程入口函数
void* make_thread_start(void* arg)
{
    while(1)
    {
        // 加锁
        pthread_mutex_lock(&g_lock);
        while(g_bowl == 1)
        {
            printf("做面人：仍有面，等待~\n");
            // 做面线程进入等待队列
            pthread_cond_wait(&g_cond_make, &g_lock);
        }
        printf("MAKE: g_bowl:%d碗面\n", ++g_bowl);
        // 解锁
        pthread_mutex_unlock(&g_lock);
        // 通知吃面等待队列中的做面线程做面
        pthread_cond_signal(&g_cond_eat);
        
    }
}

int main()
{
    // 初始化互斥锁
    pthread_mutex_init(&g_lock, NULL);
    // 初始化条件变量
    pthread_cond_init(&g_cond_eat, NULL);
    pthread_cond_init(&g_cond_make, NULL);

    pthread_t eat_thread[THREAD_COUNT];
    pthread_t make_thread[THREAD_COUNT];

    // 创建线程
    int i = 0;
    for(; i < THREAD_COUNT; ++i)
    {
        int ret = pthread_create(&eat_thread[i], NULL, eat_thread_start, NULL);
        if(ret < 0)
        {
            perror("pthread_create_eat");
            return 0;
        }
        ret = pthread_create(&make_thread[i], NULL, make_thread_start, NULL);
        if(ret < 0)
        {
            perror("pthread_create_make");
            return 0;
        }
    }
    // 主线程等待所有工作线程
    for(i = 0; i < THREAD_COUNT; ++i)
    {
        pthread_join(eat_thread[i], NULL);
        pthread_join(make_thread[i], NULL);
    }
    // 销毁互斥锁、条件变量
    pthread_mutex_destroy(&g_lock);
    pthread_cond_destroy(&g_cond_eat);
    pthread_cond_destroy(&g_cond_make);

    return 0;
}
